﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Phone.Controls;
using Newtonsoft.Json;
using WhallaToolkit.ShareServices.Exceptions;
using WhallaToolkit.ShareServices.Helpers;
using WhallaToolkit.ShareServices.Models;
using WhallaToolkit.ShareServices.Models.AccessTokens;
using WhallaToolkit.ShareServices.Services;
using WhallaToolkit.IsolatedStorage;

namespace WhallaToolkit.ShareServices.Brokers
{


    /// <summary>
    /// This class mimics the functionality provided by WebAuthenticationBroker available in Win8.
    /// </summary>
    public sealed class FacebookAuthenticationBroker
    {

        #region Fields

        private static string responseData = "";
        private static uint responseErrorDetail = 0;
        private static WebAuthenticationStatus responseStatus = WebAuthenticationStatus.UserCancel;
        private static AutoResetEvent authenticateFinishedEvent = new AutoResetEvent(false);
        private static IIsolatedStorageService isolatedStorageRepository = new IsolatedStorageService();
        private static string authenticationCode = "";
        #endregion


        #region Properties

       internal static bool AuthenticationInProgress { get;  set; }
       internal static Uri StartUri { get; set; }
       internal static Uri EndUri { get; set; }

        #endregion

        async static Task<FacebookAccessToken> AuthenticateAsync()
        {
            FacebookAccessToken returnToken = null;
            var rootFrame = Application.Current.RootVisual as PhoneApplicationFrame;
            if (rootFrame == null)
            {
                throw new InvalidOperationException();
            }

            StartUri = FacebookServices.GetLoginUrl();
            EndUri = new Uri("https://www.facebook.com/connect/login_success.html",UriKind.Absolute);
            FacebookAuthenticationBroker.AuthenticationInProgress = true;

            // Navigate to the login page.
            (Application.Current.RootVisual as PhoneApplicationFrame).Navigate(new Uri("/SocialService;component/Brokers/Facebook/FacebookConnect.xaml", UriKind.Relative));


            Task<WebAuthenticationResult> task = Task<WebAuthenticationResult>.Factory.StartNew(() =>
            {
                authenticateFinishedEvent.WaitOne();
                return new WebAuthenticationResult(responseData, responseStatus, responseErrorDetail);
            });

            WebAuthenticationResult result = await task;
            if (result.ResponseStatus == WebAuthenticationStatus.Success)
            {
                returnToken = await getAccessTokenAsync();
            }
            else if (result.ResponseStatus == WebAuthenticationStatus.UserCancel)
            {
                throw new UserCanceledAuthenticationException();
            }
            else if (result.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
            {
                throw new HttpErrorAuthenticationException();
            }
            if (returnToken != null)
            {
                isolatedStorageRepository.SaveSettings("social_facebook_tokens", JsonConvert.SerializeObject(returnToken));
            }
            return returnToken;
        }

        public static async Task<FacebookAccessToken> AuthenticateFacebookAsync()
        {
            string serializedToken = isolatedStorageRepository.LoadSettings<string>("social_facebook_tokens");

            if (serializedToken == null)
            {
                return await AuthenticateAsync();
            }
            FacebookAccessToken facebookAccessToken = JsonConvert.DeserializeObject<FacebookAccessToken>(serializedToken);
            return facebookAccessToken;
        }

        internal static void OnAuthenticationFinished(string data, WebAuthenticationStatus status, uint error, string authCode)
        {
            responseData = data;
            responseStatus = status;
            responseErrorDetail = error;
            authenticationCode = authCode;
            AuthenticationInProgress = false;

            // Signal the waiting task that the authentication operation has finished.
            authenticateFinishedEvent.Set();
        }

        static async Task<FacebookAccessToken> getAccessTokenAsync()
        {
            WebClient client = new WebClient();
            TaskCompletionSource<string> taskCompletion = new TaskCompletionSource<string>();
            client.DownloadStringCompleted += (sender, args) =>
            {
                string data = args.Result;
                data = "?" + data;

                // Acquire access_token and expires timestamp
                IEnumerable<KeyValuePair<string, string>> pairs = UriToolKits.ParseQueryString(data);
                string accessToken = KeyValuePairUtils.GetValue(pairs, "access_token");
                taskCompletion.SetResult(accessToken);
            };
            client.DownloadStringAsync(new Uri(FacebookServices.GetAccessTokenRequestUrl(authenticationCode),UriKind.Absolute));
            return new FacebookAccessToken() {Token = await taskCompletion.Task};
        }
    }
}
